package in.abip.chisame;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.LinkedList;
import java.util.Queue;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;

/**
 * Abstract class for activity that needs network connection.
 * 
 * @author Julot.
 * @since Thursday, January 20th, 2011.
 */
public abstract class NetworkActivity extends ChisameActivity {
	private Thread _udpServer = null;
	final Handler _updateUiHandler = new Handler();
	protected Queue<String> inputs = new LinkedList<String>();
	protected Queue<String> tcpOutputs = new LinkedList<String>();
	protected Queue<String> udpOutputs = new LinkedList<String>();
	private String _host = "192.168.2.50";
	private Integer _port = 6667;
	private boolean _busy = false;

	private class UdpServer extends Thread {
		private DatagramSocket _socket = null;
		private DatagramPacket _packet = null;
		private byte[] _buffer = new byte[1024];
		private Boolean _stopped = false;
		private String _tag = "UdpServer";

		public void interrupt() {
			super.interrupt();
			_stopped = true;
			_socket.close();
//			Log.d(_tag, "UDP server stopped.");
		}

		public void run() {
			String msg = "";
			msg = String.format("Running UDP Server at port %d...", _port);
			Log.d(_tag, msg);
			try {
				_socket = new DatagramSocket(_port);
			} catch (SocketException e) {
				msg = "Error creating DatagramSocket.";
				Log.d(_tag, msg);
			}
			_packet = new DatagramPacket(_buffer, _buffer.length);
			Log.d(_tag, "Receiving UDP packet...");
			try {
				while (!_stopped) {
					_socket.receive(_packet);
					String data = new String(_packet.getData());
					data = data.substring(0, _packet.getLength());
					Log.d(_tag, "Received UDP packet: " + data);
					inputs.add(data);
					_updateUiHandler.post(_updatingUi);
				}
			} catch (InterruptedIOException e) {
				Thread.currentThread().interrupt();
				Log.d(_tag, "Interupted IO Exception.");
			} catch (IOException e) {
				if (!_stopped) {
					Log.d(_tag, "Error receiving DatagramPacket.");
				}
			}
		}
	}

	private Runnable _sending = new Runnable() {
		public void run() {
			_send();
		}
	};

	final Runnable _updatingUi = new Runnable() {
		public void run() {
			updateUi();
		}
	};

	protected void updateUi() {
		String tag = "NetworkActivity.updateUi";
		String input = null;
		while ((input = inputs.poll()) != null) {
			Log.d(tag, input);
		}
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
	}

	@Override
	protected void onResume() {
		super.onResume();
		populate();
		_readSettings();
		_udpServer = new UdpServer();
		_udpServer.start();
		refresh();
	}

	@Override
	protected void onPause() {
		super.onPause();
		_udpServer.interrupt();
	}

	private void _readSettings() {
		SharedPreferences pref = getSharedPreferences(
				SettingsActivity.HARDWARE, Context.MODE_PRIVATE);
		if (pref.contains(SettingsActivity.IP)) {
			_host = pref.getString(SettingsActivity.IP, "192.168.2.50");
		} else {
			_host = "192.168.2.50";
		}
		if (pref.contains(SettingsActivity.PORT)) {
			_port = pref.getInt(SettingsActivity.PORT, 6667);
		} else {
			_port = 6667;
		}
	}

	private void _send() {
		String command = null;
		String result = null;

		_busy = true;
		UdpTelnetClient udpClient = new UdpTelnetClient();
		if (udpClient.connect(_host, _port)) {
			while ((command = udpOutputs.poll()) != null) {
				udpClient.attention(command);
			}
			udpClient.disconnect();
		} else {
			udpOutputs.clear();
		}
		
		TcpTelnetClient tcpClient = new TcpTelnetClient();
		if (tcpClient.connect(_host, _port)) {
			while ((command = tcpOutputs.poll()) != null) {
				result = tcpClient.attention(command).trim();
//				Log.d(_tag, result);
				if (result != "") {
					inputs.add(result);
				}
			}
			tcpClient.disconnect();
		} else {
			tcpOutputs.clear();
		}
		_updateUiHandler.post(_updatingUi);
		_busy = false;
	}
	
	public void send(String command) {
		udpOutputs.add(command);
		tcpOutputs.add(command);
		startSend();
	}

	protected void startSend() {
		if (!_busy) {
			Thread thread = new Thread(null, _sending, "Sending");
			thread.start();
		}
	}

}
